﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using Newtonsoft.Json;

namespace P2PTransmit.ViewModal.Service
{
    public delegate void ProtocolReceiveEventHandler(string json, IPEndPoint source);
    public abstract class ProtocolService<T>:IDisposable
    {
        private   UdpClient                                 service;
        protected IPEndPoint                                broadcast;
        protected bool                                      started;
        protected event ProtocolReceiveEventHandler         OnReceive;
        protected AsyncObservableCollection<T>              Pool;

        public ProtocolService(int port)
        {
            service = new UdpClient( port );
            broadcast = new IPEndPoint( IPAddress.Broadcast, port );
        }

        public void Start()
        {
            if(!started)
            {
                started = true;
                Task t = new Task( Loop );
                t.Start();
            }
        }

        async private void Loop()
        {
            while(started)
            {
                var r = await service.ReceiveAsync();
                try
                {
                    OnReceive( Encoding.UTF8.GetString( r.Buffer ), r.RemoteEndPoint );
                }
                catch
                {

                }
            }
        }

        async protected void Send(string json)
        {
            var data = Encoding.UTF8.GetBytes( json );
            await service.SendAsync( data, data.Length, broadcast );
        }

        public virtual void Dispose()
        {
            Pool.Clear();
            Pool = null;
            service.Dispose();
        }

        protected string Serialize(object obj) => JsonConvert.SerializeObject( obj );
        protected W Deserialize<W>(string json) => JsonConvert.DeserializeObject<W>( json );
        public virtual void CollectionBinding(AsyncObservableCollection<T> collection)
        {
            Pool = collection ?? throw new NullReferenceException();
        }
    }
}
